#!/usr/bin/python
import re
from pytz.gae import pytz
from string import Template
from datetime import datetime
from db import IdList, Db, GoogleUser
from email.utils import parsedate
from xml.sax.saxutils import unescape
from google.appengine.ext import db
from google.appengine.api import urlfetch
from config import MAX_SHORT_ID_LIST_NUM

class Utils(object):
  allow_duplicate = True

  def __init__(self, jid):
    self._jid = jid
    self._user = GoogleUser.get_by_jid(jid)

  @staticmethod
  def parse_text(text):
    return unescape(text).replace('\r\n', ' ').replace('\n', ' ').replace('\r', ' ')

  def parse_status(self, status):
    if status is None:
      return None
    if 'retweeted_status' in status and self._user.official_retweet:
      status = status['retweeted_status']
    short_id, short_id_str = self.generate_short_id(status['id'])
    if not self.allow_duplicate and short_id is None:
      return None
    msg_dict = {'content': Utils.parse_text(status['text']),
                'id': str(status['id'])}
    if 'user' in status:
      msg_dict['username'] = status['user']['screen_name']
      msg_dict['name'] = status['user']['name']
    elif 'sender' in status:
      msg_dict['username'] = status['sender']['screen_name']
      msg_dict['name'] = status['sender']['name']
    elif 'from_user' in status:
      msg_dict['username'] = status['from_user']
      msg_dict['name'] = ''
    else:
      msg_dict['username'] = ''
    Db.set_cache(status)
    if msg_dict['username'] and self._user.bold_username:
      msg_dict['username'] = '*%s*' % msg_dict['username']
    username = self._user.enabled_user
    username_at = "@" + username
    if username_at in msg_dict['content']:
      if self._user.bold_username:
        msg_dict['content'] = msg_dict['content'].replace(username_at, '*%s*' % username_at)
    msg_dict['shortid'] = '%s' % (short_id_str) if short_id is not None else ''
    utc = pytz.utc
    t = parsedate(status['created_at'])[:6]
    t = datetime(*t)
    utc_dt = utc.localize(t)
    tz = pytz.timezone(self._user.timezone)
    t = tz.normalize(utc_dt.astimezone(tz))
    msg_dict['time'] = t.strftime(self._user.date_format.encode('UTF-8')).decode('UTF-8')
    if 'source' in status:
      source = status['source'].replace('&lt;','<').replace('&gt;','>')
      source = re.match(r'<a .*>(.*)</a>', source)
      msg_dict['source'] = source.group(1) if source else status['source']
    else:
      msg_dict['source'] = ''
    return Template(unicode(self._user.msg_template)).safe_substitute(msg_dict)


  def parse_statuses(self, statuses, reverse=True, filter_self=False):
    if statuses:
      msgs = list()
      if self._user.reverse:
        reverse = not reverse
      if reverse:
        statuses.reverse()
      for status in statuses:
        if filter_self and 'user' in status and status['user']['screen_name'] == self._user.enabled_user:
          continue
        text = self.parse_status(status)
        if text is not None:
          msgs.append(text)
      return '\n'.join(msgs)
    return ''


  def generate_short_id(self, id):
    if not db.WRITE_CAPABILITY:
      return None, None
    id = str(id)
    id_list = IdList.get_by_jid(self._jid, self._user.shard)
    if id in id_list.short_id_list:
      if not self.allow_duplicate:
        return None, None
      short_id = id_list.short_id_list.index(id)
    else:
      id_list.list_pointer += 1
      id_list.list_pointer %= MAX_SHORT_ID_LIST_NUM
      id_list.short_id_list[id_list.list_pointer] = id
      IdList.set(self._jid, id_list)
      short_id = id_list.list_pointer
    short_id_str = chr(65+(short_id // 26))+chr(65+(short_id % 26))
    return short_id, short_id_str


  def restore_short_id(self, short_id):
    short_id_regex = r'^(?:\.)?([a-zA-Z]+|\d+)$'
    m = re.match(short_id_regex, str(short_id))
    if m is None:
      raise ValueError
    g = m.group(1)
    if g.isdigit():
      short_id = int(g)
    else:
      g = g.lower()
      short_id = (ord(g[0])-97)*26+(ord(g[1])-97)
    if short_id < MAX_SHORT_ID_LIST_NUM:
      id_list = IdList.get_by_jid(self._jid, self._user.shard)
      id = id_list.short_id_list[short_id]
      if id:
        return int(id)
    else:
      return short_id
    return None

def url_fetch(*args, **kwargs):
  if 'headers' in kwargs:
    kwargs['headers']['Accept-Encoding'] = 'gzip'
  else:
    kwargs['headers'] = {'Accept-Encoding': 'gzip'}
  result = urlfetch.fetch(*args, **kwargs)
  response = result.content
  if result.headers.get('content-encoding', None) == 'gzip':
    import zlib

    try:
      response = zlib.decompress(response, 16 + zlib.MAX_WBITS)
    except zlib.error:
      pass
  return response
